package com.taobao.classloader;

import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class JarClassLoader extends ClassLoader {
	private static Logger			logger			= LoggerFactory.getLogger(JarClassLoader.class);
	private Map<String, Class<?>>	classes			= new WeakHashMap<String, Class<?>>();

	protected boolean				monitorOn		= true;
	protected boolean				sourceMonitorOn	= true;

	private ClassLoader				parent;
	private ClassLoadStrategy		classLoadStrategy;
	private JarResources			jarResources;

	public JarClassLoader() {
	}

	public JarClassLoader(List<String> jarName, ClassLoader parent) {
		this.parent = parent;
		jarResources = new JarResources(jarName);
	}

	public JarClassLoader(ClassLoaderScope scope, ClassLoader parent) {
		this.parent = parent;
		this.jarResources = new JarResources(scope.getJarPackagePath());
		this.classLoadStrategy = scope.getLoadStrategy();
		if (!scope.isLazyLoadResources()) {
			jarResources.init();
		}
	}

	public Class<?> loadClass(String className) throws ClassNotFoundException {
		return (loadClass(className, true));
	}

	public synchronized Class<?> loadClass(String className, boolean resolveIt) throws ClassNotFoundException {
		Class<?> result = null;
		result = (Class<?>) classes.get(className);
		if (result != null) {
			logger.debug("Returning cached class: {}",className);
			return result;
		} else {
			result = classLoadStrategy.loadClass(className, this, parent);
		}

		if (result == null) {
			throw new ClassNotFoundException(className);
		}
		if (resolveIt)
			resolveClass(result);
		classes.put(className, result);
		logger.debug("Returning newly loaded class: {}",className);
		return result;
	}

	public Class<?> loadClassFromResource(String className) {
		byte[] classBytes = jarResources.getClassResource(className);
		if (classBytes != null && classBytes.length > 0) {
			return defineClass(className, classBytes, 0, classBytes.length);
		} else {
			return null;
		}
	}
}
